package com.luboyan.CBillbill.service.elasticsearch.impl;

import com.luboyan.CBillbill.dao.file.Video;
import com.luboyan.CBillbill.dao.user.UserInfo;
import com.luboyan.CBillbill.repository.UserInfoRepository;
import com.luboyan.CBillbill.repository.VideoRepository;
import com.luboyan.CBillbill.service.elasticsearch.ElasticSearchService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class ElasticSearchServiceImpl implements ElasticSearchService {

    @Autowired
    private VideoRepository videoRepository;

    @Autowired
    private UserInfoRepository userInfoRepository;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 将视频信息放入ES中
     */
    @Override
    public void addVideo(Video video) {
        videoRepository.save(video);
    }

    /**
     * 模糊查询视频
     */
    @Override
    public Video getVideos(String key) {
       return videoRepository.findByTitleLike(key);
    }

    /**
     * 删除所有视频
     */
    @Override
    public void deleteAllVideos() {
        videoRepository.deleteAll();
    }

    /**
     * 存储用户信息
     */
    @Override
    public void addUserInfo(UserInfo userInfo) {
        userInfoRepository.save(userInfo);
    }

    /**
     * 删除所有用户信息
     */
    @Override
    public void deleteAllUserInfos() {
        userInfoRepository.deleteAll();
    }

    /**
     * 海量资源查询
     */
    @Override
    public List<Map<String, Object>> getContents(String key, Integer page, Integer pageSize) throws IOException {
        String[] indices = {"videos","user-infos"};  //ES中的索引组
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();  //配置类
        sourceBuilder.from(page - 1);  //页码
        sourceBuilder.size(pageSize);  //分页大小
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));  //超时设定

        MultiMatchQueryBuilder matchQueryBuilder =
                QueryBuilders.multiMatchQuery(key, "title", "nick", "description"); //多条件检索配置
        sourceBuilder.query(matchQueryBuilder);

        //key高亮显示
        String[] array = {"title", "nick", "description"};
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        for(String k:array){
            //将存储字段的位置找到替换为需要高亮的字段类型
            highlightBuilder.fields().add(new HighlightBuilder.Field(k));
        }
        highlightBuilder.requireFieldMatch(false);  //如果多个字段进行高亮，需要配置为false
        //对高亮内容进行前后标签添加
        highlightBuilder.preTags("<span style=\"color:red\">");
        highlightBuilder.postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);

        SearchRequest searchRequest = new SearchRequest(indices);  //返回的结果
        searchRequest.source(sourceBuilder);

        //执行搜索
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //装填结果
        List<Map<String, Object>> result = new ArrayList<>();
        for(SearchHit hit: searchResponse.getHits()){  //匹配到的条目
            //处理高亮字段
            //TODO:这是因为我们在上面的高亮设置中为相应的字段内容进行了标签添加
            //TODO：但是发送给前端的得是字符串类型才行
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();  //获取高亮区域
            Map<String, Object> sourceMap = hit.getSourceAsMap();  //查询的内容
            for(String k1: array){
                HighlightField field = highlightFields.get(k1);
                if(field != null){
                    Text[] fragments = field.fragments();  //获取这个字段下的内容
                    String str = Arrays.toString(fragments);
                    str = str.substring(1, str.length()-1); //去掉[]
                    sourceMap.put(k1, str);  //替换查询的结果中的值
                }
            }
            result.add(sourceMap);
        }
        return result;
    }
}
